/* Version : 1.2
 * 1, just show a frame 
 * 2, add a text area & a text field to the Frame.
 * 3, 实现关闭按钮事件响应(使用匿名类)
 * 4, 实现回车后将txtField中文本发送到txtArea中(使用内部类)
 * 5, 添加服务端代码-chatServer
 * 6, Client端中添加Connect方法,用于连接Server
 * 7, Client连接到Server后可以向Server发送消息
 * 8, Clinet可以往Server中多次发送消息
 * 9, 修复Client关闭后导致Server中的EOF异常及server端口被占用时的异常
 * 10, 解决多客户端连接(*线程/异步)
 * 11, 服务器端增加消息转发功能, 使用对象容器保存连接的客户端socket.
 * 12, 客户端增加线程,接受服务器端消息转发
 * 20, 服务器端增加GUI, 启动时根据参数判断是否加载界面
 */
package com.knightsoft.desktopapp.jchatsystem;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.metal.MetalLookAndFeel;

@SuppressWarnings("serial")
public class ChatClient extends JFrame {
	public static final int WINDOW_WIDTH  = 400;
	public static final int WINDOW_HEIGHT = 300;
	
	private Boolean bConn = false;
	private Socket socket = null;
	private DataOutputStream dos = null;
	private DataInputStream dis = null;
	private JTextField txtField = new JTextField();
	private TextArea txtArea = new TextArea();
	private Thread tRec = new Thread(new Receiver());
	private Panel panel = new Panel(new FlowLayout());
	private JLabel lblHost = new JLabel("Host: ");
	private JTextField txtHost = new JTextField("127.0.0.1",19);
	private JLabel lblPort = new JLabel("Port: ");
	private JTextField txtPort = new JTextField("2000", 5);
	private JButton btnConn = new JButton("Connect");
	

	public static void main(String[] args) {
		UIManager.put("swing.boldMetal", Boolean.FALSE);
        JDialog.setDefaultLookAndFeelDecorated(true);
        JFrame.setDefaultLookAndFeelDecorated(true);

        try {
            UIManager.setLookAndFeel(new MetalLookAndFeel());
        }  
        catch ( UnsupportedLookAndFeelException e ) {
            System.out.println ("Metal Look & Feel not supported on this platform. \nProgram Terminated");
            System.exit(0);
        }
        
		new ChatClient().launchFrame();
	}

	public void launchFrame() {
		
		setTitle("LAN Talker Client");
		setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
		int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
		int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
		
		setLocation( (screenWidth - WINDOW_WIDTH) / 2,
				     (screenHeight - WINDOW_HEIGHT) / 2);
		setResizable(false);
		//ImageIcon icon = new ImageIcon("res/user.png");
		ImageIcon icon = new ImageIcon(ChatClient.class
				.getResource("/user.png"));
		setIconImage(icon.getImage());
		// add the text control to frame
		btnConn.addMouseListener( new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				connect(txtHost.getText(), Integer.parseInt(txtPort.getText()));
				tRec.start();
			}
		} );
		
		panel.add(lblHost);
		panel.add(txtHost);
		panel.add(lblPort);
		panel.add(txtPort);
		panel.add(btnConn);
		//panel.validate();
		
		add(txtArea, BorderLayout.CENTER);
		add(panel, BorderLayout.NORTH);
		add(txtField, BorderLayout.SOUTH);
		// remove the blank area
		pack();
		// 0.3: close button
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				disConnect();
				System.exit(0);
			}
		});
		txtField.addActionListener(new TFListener());
		setVisible(true);
		
		// version 0.6
		
		// Moved to Button Listener
		//connect(txtHost.getText(), Integer.parseInt(txtPort.getText()));
		//tRec.start();
	}

	// 4. 将文本发送到txtArea
	private class TFListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent ae) {
			String buffer = "[" + socket.getLocalAddress()+ ":" + socket.getLocalPort() + "]-" + txtField.getText().trim();
			// txtArea.setText(buffer);
			txtField.setText("");

			// Version .7
			try {
				// DataOutputStream dos = new
				// DataOutputStream(socket.getOutputStream());
				dos.writeUTF(buffer);
				dos.flush();
				// dos.close();
			} catch (IOException ioe) {
				ioe.printStackTrace();
			}
		}
	}

	// version 0.6
	public void connect() {
		try {
			socket = new Socket("127.0.0.1", 2000);
			System.out.println("Client: Connect to server ...");
			bConn = true;
			dos = new DataOutputStream(socket.getOutputStream());
			dis = new DataInputStream(socket.getInputStream());
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (ConnectException e) {
			System.out.println("Client: Server not found ...");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	public void connect(String ipAddr, int port) {
		try {
			socket = new Socket(ipAddr, port);
			System.out.println("Client: Connect to server ...");
			bConn = true;
			dos = new DataOutputStream(socket.getOutputStream());
			dis = new DataInputStream(socket.getInputStream());
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (ConnectException e) {
			System.out.println("Client: Server not found ...");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// version 0.8
	public void disConnect() {
		try {
			if (dos != null) dos.close();
			if (dis != null) dis.close();
			if (socket != null) socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		/*
		try {
			bConn = false;
			tRec.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			try {
				dos.close();
				dis.close();
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		*/
	}

	private class Receiver implements Runnable {

		@Override
		public void run() {
			try {
				while (bConn) {
					String msg = dis.readUTF();
					txtArea.setText(txtArea.getText() + msg + '\n');
				}
			} catch (SocketException e) {
				System.out.println("Client Quit...");
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}
}
